# -*- coding: utf-8 -*-
from django.template import Context, RequestContext, loader
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import login as _login
from django.contrib.auth.forms import UserCreationForm
from django.db import transaction
from django.db.models import Q
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.core.urlresolvers import reverse
from django.forms.models import modelformset_factory
from django.shortcuts import get_object_or_404
from django import forms
from django.forms.widgets import TextInput
from django.contrib.auth.models import User
from skoolmaster.general.common import render_template, CodeListTable, maintainer_required, lecturer_or_administrator_required, show_model_results_view, administrator_required, read_only
from skoolmaster.general.forms import PostForm, RegionForm, CountryForm, FacultyForm, LecturerUserForm, EnrollmentForm, SubjectManageForm
from skoolmaster.general.models import UserProfile, EnrollmentSubject
from skoolmaster.general.search import student_search_logic, name_search_logic,\
    id_or_name_search_logic
from skoolmaster.syllabus.models import Subject, FacultyYear, SchoolYear, UniversityProgram, ArchiveAlreadyExists
from skoolmaster.syllabus.forms import SubjectForm, UniversityProgramForm, FacultyYearForm
from skoolmaster.exams.forms import ExamApplicationForm

def login(request):
  """
  Login wrapper.
  """
  # When the user is authenticated even before the login form is shown, just
  # redirect to the dashboard
  if request.user.is_authenticated():
    return HttpResponseRedirect(reverse('welcome'))
  
  response = _login(request)
  
  # If we have been successfully authenticated, execute model-specific bookkeeping
  if request.user.is_authenticated():
    request.user.message_set.create(message = u"0|Uspešno ste se prijavili v sistem Skoolmaster!")
  
  return response

@login_required
def welcome(request):
  """
  Displays a welcome page.
  """
  return render_template(request, 'general/welcome.html')

@login_required
@administrator_required
def student_search(request, template = 'general/student_search.html', vars = {}):
  """
  View for handling student searches.
  """
  return show_model_results_view(request, template,
    queryset = UserProfile.objects.exclude(student_number = None),
    fields = [
      { 'desc' : u"Vpisna št.", 'name' : "student_number" },
      { 'desc' : u"Priimek", 'name' : "surname" },
      { 'desc' : u"Ime", 'name' : "name" },      
    ],
    vars = vars,
    show_search = True,
    search_logic = student_search_logic,
    default_sort_field = 'surname'
  )

# Models used as code-lists
CODELISTS = {
  0 : CodeListTable(0, u'Pošte', PostForm),
  1 : CodeListTable(1, u'Občine', RegionForm),
  2 : CodeListTable(2, u'Države', CountryForm),
  3 : CodeListTable(3, u'Fakultete', FacultyForm),
  4 : CodeListTable(4, u'Predmeti', SubjectForm),
  5 : CodeListTable(5, u'Študijski programi', UniversityProgramForm),
  6 : CodeListTable(6, u'Predavatelji', LecturerUserForm),
}

def cont_url(codelist):
  """
  Create a continue URL for the code-list id
  """
  return reverse('codelist_action', kwargs = {'codelist' : codelist, 'action' : 'edit'})

def ret_addr(request):
  """
  Parse the return address from the request full path.
  """
  ident = 'ret='
  ret_idx = request.get_full_path().find(ident)
  return request.get_full_path()[ret_idx + len(ident):]

@login_required
@maintainer_required
def codelist_edit(request, codelist=None, action=None, message=None):
  """
  View for handling the editing of code-lists.
  """
  if codelist and action:
    # Prepare the entry CodeListTable object and the selected model class
    entry = CODELISTS.get(int(codelist))
    if not entry:
      raise Http404
    
    modelClass = entry.formClass.model
    # Handle the adding of a code into a code-list
    if action == 'add':
      if request.method == 'POST':
        form = entry.formClass(request.POST)
        if form.is_valid():
          form.save()
          request.user.message_set.create(message = u'0|Vnos šifranta uspel.')
          return HttpResponseRedirect(reverse('codelists'))
      else:
        form = entry.formClass()
      return render_template(request, 'general/codelists/add.html', {'form' : form})
    
    # Display all entries 
    elif action == 'edit':
      if modelClass == LecturerUserForm:
        queryset = modelClass.objects.filter(user__groups = 2)
      else:
        queryset = modelClass.objects.all()
      # Name to order by
      if modelClass._meta.ordering:
        ordering_name = modelClass._meta.ordering[0]
      else:
        try:
          ordering_name = 'name' if 'name' in dir(queryset[0]) else 'pk'
        except IndexError:
          ordering_name = 'pk'
      
      return show_model_results_view(request, 'general/codelists/display.html',
        queryset = queryset,
        fields = [
          { 'desc' : u"Vnos", 'name' : ordering_name },
          { 'desc' : u"Veljavnost", 'name' : "disabled" },
          { 'desc' : u"Uredi", 'name' : "" },
          { 'desc' : u"Briši", 'name' : "" }
        ],
        show_search = True,
        search_logic = entry.formClass.search_logic,
        vars = {'codelist' : codelist, 'ret_addr' : request.get_full_path() }
      )
  return render_template(request, 'general/codelists/codelists.html', {'codelists' : CODELISTS.values()})

@login_required
@maintainer_required
def code_edit(request, codelist=None, code=None, action=None, ret=None):
  """
  Handles the editing of code-list entries.
  """ 
  if codelist and code and action:
    # Prepare the entry CodeListTable object..
    entry = CODELISTS.get(int(codelist))
    if not entry:
      raise Http404
    
    # ..and the selected code entry
    modelClass = entry.formClass.model
    try:
      modelEntry = modelClass.objects.get(pk = code)
    except:
      raise Http404    
    
    # Handle the requested actions
    if action == 'edit':
      if request.method == 'POST':
        # Use the form data to edit the existing entry
        form = entry.formClass(request.POST, instance = modelEntry, edit = True, prefix = 'base')
        # Check for single form case or two form case
        if form.is_valid():
          form.save()
          request.user.message_set.create(message = u'0|Popravljanje šifranta uspešno.')
          return HttpResponseRedirect(ret_addr(request))
      else:
        # Display the form for the selected code
        form = entry.formClass(instance = modelEntry, prefix = 'base', edit = True)
      return render_template(request, 'general/codelists/edit.html', {'form' : form, 'ret_addr' : request.get_full_path() })
      
    if action == 'del':
      if request.method == 'POST':
        # Now we can delete the entry
        modelEntry.delete()
        # Also delete the user object in the case of user profile
        if entry.formClass == LecturerUserForm:
          modelEntry.user.delete()
        request.user.message_set.create(message = u'0|Brisanje šifranta uspešno.')
        return HttpResponseRedirect(ret_addr(request))
      else:
        return render_template(request, 'general/codelists/del.html', {'entry' : modelEntry})


@login_required
@administrator_required
def enrollment_add_form(request, program_id = None, facultyyear_id = None, student_number = None, action='old'):      
  if program_id and facultyyear_id:
    program = get_object_or_404(UniversityProgram, id = program_id)
    faculty_year = get_object_or_404(FacultyYear, pk = facultyyear_id)    
    student = get_object_or_404(UserProfile, student_number = student_number) if student_number else None  
                  
    if request.method == 'POST' :      
     
      form = EnrollmentForm(request.POST, faculty_year = faculty_year)      
                  
      if form.is_valid():
         
        exit_code = form.save(program, faculty_year)
        
        if exit_code:
          request.user.message_set.create(message = exit_code)
        else:
          request.user.message_set.create(message = u"0|Uspešno ste vpisali študenta v letnik!")
          return HttpResponseRedirect(reverse('enrollment_add'))
  
   
    else:
      form = EnrollmentForm(faculty_year = faculty_year, student = student)              
    
    return render_template(request, 'general/enrollments/enrollment_add.html', {'form':form, 'program':program, 'faculty_year':faculty_year})    


@login_required
@administrator_required
def enrollment_add(request, program_id = None, facultyyear_id = None):
  """
  Handles the enrollment of student.
  """ 
      
  # select old student
  if facultyyear_id:
    return show_model_results_view(
      request, 
      'general/enrollments/student_list.html', 
      queryset = UserProfile.objects.exclude(student_number = None),
      fields = [
        { 'desc' : u"Vpisna št.", 'name' : "student_number" },
        { 'desc' : u"Priimek", 'name' : "surname" },
        { 'desc' : u"Ime", 'name' : "name" },
        { 'desc' : "", 'name' : "" },      
      ],
      vars = {'program_id':program_id, 'facultyyear_id':facultyyear_id},
      show_search = True,
      search_logic = student_search_logic,
      default_sort_field = 'surname',
      printable = False
    )    
  
  # faculty year table
  if program_id:
    program = get_object_or_404(UniversityProgram, id = program_id)
  
    return show_model_results_view(request, 'general/enrollments/facultyyear_list.html',
      queryset = FacultyYear.objects.filter(university_programs = program),
      fields = [
        { 'desc' : u"Letnik", 'name' : "name" },
        { 'desc' : u"Novi študent", 'name' : "" },
        { 'desc' : u"Stari študent", 'name' : "" },
      ],
      show_search = True,
      search_logic = FacultyYearForm.search_logic,
      vars = {'program_id':program_id}
    )    
      
  return show_model_results_view(request, 'general/enrollments/program_list.html',
    queryset = UniversityProgram.objects.all().exclude(disabled = True),
    fields = [
      { 'desc' : u"Program", 'name' : "name" },
    ],
    show_search = True,
    search_logic = UniversityProgramForm.search_logic
  )

@login_required
@administrator_required
def subjects_manage(request, student_number = None, school_year = None):
  if not student_number:
    return show_model_results_view(request, 'general/enrollments/subjects/students.html',
      queryset = UserProfile.objects.exclude(student_number = None).exclude(enrollment_forms = None),
      fields = [
        { 'desc' : u"Vpisna št.", 'name' : "student_number" },
        { 'desc' : u"Priimek", 'name' : "surname" },
        { 'desc' : u"Ime", 'name' : "name" },     
      ],
      vars = {},
      show_search = True,
      search_logic = student_search_logic,
      default_sort_field = 'surname'
    )  

  if not school_year:
    return show_model_results_view(request, 'general/enrollments/subjects/schoolyears.html',
      queryset = SchoolYear.objects.filter(enrollments__student__student_number = student_number),
      fields = [
        { 'desc' : u"Šolsko leto", 'name' : "name" },
      ],
      vars = {'student_number':student_number},
      show_search = True,
      search_logic = name_search_logic,
      default_sort_field = 'name'
    )  
  
  faculty_year = FacultyYear.objects.get(
                    enrollments__student__student_number = student_number, 
                    enrollments__school_year__name = school_year)
  
  student = get_object_or_404(UserProfile, student_number = student_number)
  enr = student.enrollment_forms.get(school_year__name = school_year)                  
  enr_subs = EnrollmentSubject.objects.filter(enrollment = enr, module = 'Izbirni predmeti')  
  elective_subjects = [sub.subject for sub in enr_subs]
  modules = enr.modules.all()
  
    
  if request.method == 'POST' :               
    form = SubjectManageForm(request.POST, 
              faculty_year = faculty_year, 
              elective_subjects = elective_subjects, 
              modules = modules)                
    if form.is_valid():
       
      exit_code = form.save(pre_elective_subjects = elective_subjects, student = student, enr = enr, pre_modules = modules)
      
      if exit_code:
        request.user.message_set.create(message = exit_code)
      else:
        request.user.message_set.create(message = u"0|Uspešno ste nastavili izbirni del predmetnika!")
        return HttpResponseRedirect(reverse('subjects_manage'))
 
  else:    
    form = SubjectManageForm(faculty_year = faculty_year, 
              elective_subjects = elective_subjects, 
              modules = modules)              
  
  return render_template(request, 'general/enrollments/subjects/manage_subject.html', {'form' : form, 'student' : student, 'school_year' : school_year, 'faculty_year' : faculty_year })  
  
@login_required
@maintainer_required
def subjects_list(request, program_id = None, school_year = None):    

  if program_id:
      year = get_object_or_404(SchoolYear, name = school_year)
      
      # Attempt to regenerate the archive (this will fail for all but the latest year);
      # needed to keep the latest year up to date
      try:
        year.archive_year()
      except ArchiveAlreadyExists:
        pass
            
      archive = year.get_archive()
      if program_id not in [program['id'] for program in archive]:
        raise Http404
      
      program = [program for program in archive if program['id'] == program_id][0]
           
      
      return render_template(request, 'general/subjectslist/subjects.html', 
                                      {'program':program, 'school_year': school_year, 'print_view' : request.GET.get('print', '')}
                            )
      
      
  if school_year:
    year = get_object_or_404(SchoolYear, name = school_year)
    
    return render_template(request, 'general/subjectslist/program_list.html',
                            {'fields'         : [{ 'desc' : u"Študijski programi za leto %s" % school_year, 'name' : "name" },],
                             'programs'       : year.get_archive(),
                             'school_year'    : school_year}
                           )     
              
      
  return show_model_results_view(request, 'general/subjectslist/schoolyear_list.html',
    queryset = SchoolYear.objects.all(),
    fields = [
      { 'desc' : u"Šolsko leto", 'name' : "name" },
    ],
    show_search = True,    
    search_logic = id_or_name_search_logic
  )  

@login_required
@administrator_required    
def personal_data(request, user_id = None):
  """
  Displays a students personal data.
  """
  if user_id:
    userProfile = get_object_or_404(UserProfile, pk = user_id)
    return render_template(request, 'general/personal_data.html', 
                           {'user_profile' : userProfile,
                            'print_view' : request.GET.get('print', '')})
  
  return student_search(requst)